package com.fingard.dsp;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fingard.FGBiz;
import com.fingard.client.DspClient;
import com.fingard.cluster.ClusterCenter;
import com.fingard.cluster.HostInfo;
import com.fingard.constant.Format;
import com.fingard.db.ConnSet;
import com.fingard.db.JDBCHelper;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.bank.DealDirectBank;
import com.fingard.dsp.bank.directConfig.BankConfig;
import com.fingard.dsp.bank.directConfig.ListenerSet;
import com.fingard.dsp.bank.directConfig.TaskTimerSet;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.dsp.bank.reqrespobj.diagnostics.RetAtsBankFrontStatus;
import com.fingard.dsp.bank.reqrespobj.diagnostics.detail.RetAtsFrontStatusDetail;
import com.fingard.dsp.bank.reqrespobj.dsplog.RetAtsDSPLog;
import com.fingard.dsp.bank.reqrespobj.dsplog.detail.RetAtsDSPLogDetail;
import com.fingard.dsp.bank.scheduler.TaskExecutor;
import com.fingard.dsp.bankset.*;
import com.fingard.dsp.bizbasic.BizObjectCol;
import com.fingard.dsp.core.DSPSecurityData;
import com.fingard.dsp.core.dao.security.EncodeSaltValueMapper;
import com.fingard.dsp.core.dao.security.IPWhiteListMapper;
import com.fingard.dsp.entity.po.EncodeSaltValuePO;
import com.fingard.dsp.entity.po.IPWhiteListPO;
import com.fingard.dsp.tcpserver.PayQryController;
import com.fingard.dsp.tcpserver.RequestNIO;
import com.fingard.io.FileHelper;
import com.fingard.luna.framework.boot.core.util.SpringContextHolder;
import com.fingard.net.TcpReceiver;
import com.fingard.net.listener.HttpListener;
import com.fingard.remoting.server.TenantItem;
import com.fingard.text.StringHelper;
import com.fingard.util.DateHelper;
import com.fingard.xml.XmlTextReader;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

//import fingard.net.listener.HttpListener;

public class DSPCenter {
    
    private static Object lockMutex = new Object();
    public BizObjectCol bizObjCol = null;
    public BankFrontCenter bankFrontCenter = null;
    public BankConfig dspConfig = null;
    public DSPSet dspSet = null;
    public String dspCode = "";
    public boolean dbLogOnlySavePath = false;
    public ConnSet dbConnectionSet = null;
    public boolean enableDbLog = false;
    public String bankLogsFirstDir = null;
    public String dataDirPath = "";
    public String charset = "gbk";
    public String rootDirPath = "";
    public String bankLogsDirPath = "";
    public boolean convertBankArea = false;
    public boolean convertPayState = false;
    public boolean enableCacheCurTrans = false;
    public boolean enableCacheHisTrans = false;
    public boolean enableAutoTodayTrans = false;
    public boolean enableAutoHisTrans = false;
    public boolean enableCheckTransSeqID = false;
    public boolean qryByEachDay7516 = false;
    public boolean disableAibank = false;
    ScheduledExecutorService pool = null;
    //private String logNowTableName = "";
    private HashMap<String, String> hashTableName = new HashMap<String, String>();
    private ArrayList<Thread> threadArray = null;
    private HashMap<Integer,HttpListener> mapListener = null;
    private ArrayList<TaskTimerSet> taskList = null;
    
    private PayQryController payQryCtrl;//支付状态查询控制，支付如果还未执行结束，则不允许查询
    
    /**获取支付状态查询控制对象，用于控制当支付还未执行结束，则不允许查询*/
    public PayQryController getPayQryController(){
    	return payQryCtrl;
    }
    

    public DSPCenter(String p_mainDir) throws Exception {
    	dspSet = new DSPSet();
    	rootDirPath = StringHelper.trimEndFileSp(p_mainDir);
    	dspSet.rootDirPath = rootDirPath;
    	bankLogsDirPath = rootDirPath;
    	dspSet.bankLogsDirPath = bankLogsDirPath;
    	dspSet.dataDirPath = dspSet.rootDirPath;
    	payQryCtrl = new PayQryController();
        bizObjCol = new BizObjectCol();
        refreshDSPSystem();
        bankFrontCenter = new BankFrontCenter(dspSet);//需先加载DSPSystem

        //初始化IP白名单, 盐值等安全数据
        initSecurityData();
    }

    //加载IP白名单到内存中
    private void initSecurityData() {
        //获取bankFront中的所有租户ID
        HashMap<String, BankFrontBalance> hashMapBankFront = this.bankFrontCenter.hashMapBankFront;
        for (Map.Entry<String, BankFrontBalance> entry : hashMapBankFront.entrySet()) {
            BankFrontBalance bankFrontBalance = entry.getValue();
            for (BankFront bankFront : bankFrontBalance.listBankFront) {
                if (StringHelper.hasAnyChar(bankFront.tenant)) {
                    DSPSecurityData.getInstance().getTenantIdSet().add(bankFront.tenant);
                }
            }
        }
        //根据TenantId查询所有IP白名单,若从数据库中查找不到, 就从配置文件中读取
        if (DSPSecurityData.getInstance().isReadFileFlag()) {
            //打印日志
            FGBiz.startLog.addLog("读取文件版IP白名单和盐值");
            getSecurityDataFromXml();
        } else {
            for (String tenantId : DSPSecurityData.getInstance().getTenantIdSet()) {
                getSecurityDataFromDb(tenantId);
            }
        }
    }

    /**
     * 从XML文件中读取IP白名单和盐值
     */
    private void getSecurityDataFromXml() {
        //IP白名单
        String filePath = FGBiz.DSPHOME + File.separator + "config" + File.separator + "IPWhiteList.xml";
        if (!FileHelper.existFile(filePath)) {
            FGBiz.startLog.addLog("IP白名单配置文件不存在");
            return;
        }
        try {
            String configText = FileHelper.readFileText(filePath, "utf-8");
            XmlTextReader reader = new XmlTextReader(configText);
            while (reader.read("/config/IPWhite")) {
                String tenantId = reader.readedXElement.getSingleTextNotNull("tenantid");
                if ("1".equals(reader.readedXElement.getSingleTextNotNull("isactive"))) {//有效
                    if (DSPSecurityData.getInstance().getIpWhiteList().get(tenantId) != null) {
                        DSPSecurityData.getInstance().getIpWhiteList().get(tenantId)
                                .add(reader.readedXElement.getSingleTextNotNull("ip"));
                    } else {
                        List<String> ips = new ArrayList();
                        ips.add(reader.readedXElement.getSingleTextNotNull("ip"));
                        DSPSecurityData.getInstance().getIpWhiteList().put(tenantId, ips);
                    }
                }
            }
            //盐值
            filePath = FGBiz.DSPHOME + File.separator + "config" + File.separator + "EncodeSaltValue.xml";
            if (!FileHelper.existFile(filePath)) {
                FGBiz.startLog.addLog("加密盐值配置文件不存在");
                return;
            }
            configText = FileHelper.readFileText(filePath, "utf-8");
            reader = new XmlTextReader(configText);
            Date currDate = new Date();
            while (reader.read("/config/EncodeSaltValue")) {
                String tenantId = reader.readedXElement.getSingleTextNotNull("tenantid");
                if ("1".equals(reader.readedXElement.getSingleTextNotNull("isactive")) &&
                        DateHelper.getDifferSecs(currDate, Format.DateTimeFormat.parse(
                                reader.readedXElement.getSingleTextNotNull("invaliddate"))) < 0) {//有效
                    EncodeSaltValuePO po = new EncodeSaltValuePO();
                    po.setIsactive("1");
                    po.setValiddate(Format.DateTimeFormat.parse(
                            reader.readedXElement.getSingleTextNotNull("validdate")));
                    po.setInvaliddate(Format.DateTimeFormat.parse(
                            reader.readedXElement.getSingleTextNotNull("invaliddate")));
                    po.setSaltvalue(reader.readedXElement.getSingleTextNotNull("saltvalue"));
                    po.setDescription(reader.readedXElement.getSingleTextNotNull("description"));
                    po.setTenantid(Integer.parseInt(reader.readedXElement.getSingleTextNotNull("tenantid")));

                    if (DSPSecurityData.getInstance().getEncodeSaltValues().get(tenantId) != null) {
                        DSPSecurityData.getInstance().getEncodeSaltValues().get(tenantId).add(po);
                    } else {
                        List<EncodeSaltValuePO> encodeSaltValuePOS = new ArrayList();
                        encodeSaltValuePOS.add(po);
                        DSPSecurityData.getInstance().getEncodeSaltValues().put(tenantId, encodeSaltValuePOS);
                    }
                }
            }
        } catch (Exception e) {
            FGBiz.limitMsg.exception("DSPCenter.getSecurityDataFromXml", e);
        }
    }

    /**
     * 从数据库中读取IP白名单和盐值
     * @param tenantId
     */
    private void getSecurityDataFromDb(String tenantId) {
        IPWhiteListMapper mapper = SpringContextHolder.getBean(IPWhiteListMapper.class);
        EncodeSaltValueMapper encodeSaltMapper = SpringContextHolder.getBean(EncodeSaltValueMapper.class);
        QueryWrapper<IPWhiteListPO> queryIPWrapper = new QueryWrapper<>();
        queryIPWrapper.eq("TENANTID", tenantId).eq("ISDELETE", "0")
                .eq("ISACTIVE", "1");
        List<String> ips = new ArrayList<>();
        for (IPWhiteListPO ipWhiteListPO : mapper.selectList(queryIPWrapper)) {
            ips.add(ipWhiteListPO.getIp());
        }
        if (ips.size() > 0) {
            DSPSecurityData.getInstance().getIpWhiteList().put(tenantId, ips);
        }
        //盐值
        QueryWrapper<EncodeSaltValuePO> queryEncodeSaltWrapper = new QueryWrapper<>();
        Date currDate = new Date();
        queryEncodeSaltWrapper.eq("TENANTID", tenantId).eq("ISDELETE", "0").eq("ISACTIVE", "1")
                .gt("INVALIDDATE", currDate).orderByAsc("VALIDDATE");
        //根据TenantId查询所有盐值
        List<EncodeSaltValuePO> encodeSaltValuePOS = encodeSaltMapper.selectList(queryEncodeSaltWrapper);
        if (encodeSaltValuePOS != null && encodeSaltValuePOS.size() > 0) {
            DSPSecurityData.getInstance().getEncodeSaltValues().put(tenantId, encodeSaltValuePOS);
        }
    }


    public static ReqRespHeader getReqRespHeader(XmlTextReader xmlReader) throws Exception {
        ReqRespHeader tmpHeader = new ReqRespHeader();
        xmlReader.backToTop();
        tmpHeader.bankCode = xmlReader.getSimpleTextNotNull("BankCode");
        tmpHeader.srcBankCode = tmpHeader.bankCode;
        if (tmpHeader.bankCode.startsWith("CSRS")) {
            tmpHeader.bankCode = "CSRSYBT11";
        }
        tmpHeader.transType = xmlReader.getSimpleText("TransType");
        if ("Contract".equalsIgnoreCase(tmpHeader.transType) || "QryContract".equalsIgnoreCase(tmpHeader.transType)
                || "QryBatContract".equalsIgnoreCase(tmpHeader.transType) || "UpContract".equalsIgnoreCase(tmpHeader.transType)
                || "DeContract".equalsIgnoreCase(tmpHeader.transType) || "QryDeContract".equalsIgnoreCase(tmpHeader.transType)) {
            if (tmpHeader.bankCode != null && tmpHeader.bankCode.startsWith("FnGrd") && tmpHeader.bankCode.length() == 8) {
                tmpHeader.bankCode = "FnGrd01";
            }
        }
        tmpHeader.step = xmlReader.getSimpleTextNotNull("Step");
        tmpHeader.logTransID = xmlReader.getSimpleTextNotNull("LogTransID");
        String filterNdName = "/ATSYH/TransReq/TransParam/DetailRecord";
        tmpHeader.corporation = xmlReader.getSimpleTextByFilter("Entity", filterNdName);//
        tmpHeader.group = xmlReader.getSimpleTextByFilter("SystemCode", filterNdName);
        if(StringHelper.isNullOrEmpty(tmpHeader.group)){
        	tmpHeader.group = xmlReader.getSimpleTextByFilter("Group", filterNdName);
        }
        tmpHeader.transSeqID = xmlReader.getSimpleText("TransSeqID");
        
        
        tmpHeader.tenant = xmlReader.getSimpleTextByFilter("Tenant", filterNdName);
        if(StringHelper.isNullOrEmpty(tmpHeader.tenant)){
        	tmpHeader.tenant = "";
        }
        tmpHeader.commandCode = xmlReader.getSimpleText("CommandCode");
        tmpHeader.actBankType = xmlReader.getSimpleText("ActBankType");
        tmpHeader.transTime = xmlReader.getSimpleText("TransTime");
        tmpHeader.psselNum = xmlReader.getSimpleText("PsselNum");
        tmpHeader.reqSeqID = xmlReader.getSimpleText("ReqSeqID");
        if("1908BAT".equals(tmpHeader.transType) || "1944BAT".equals(tmpHeader.transType) || "1908".equals(tmpHeader.transType) || "1944".equals(tmpHeader.transType)){
        	tmpHeader.reqSeqOrBatNo = xmlReader.getSimpleText("ReqBatchNO");
        }
        if(StringHelper.isNullOrEmpty(tmpHeader.reqSeqOrBatNo)){
        	tmpHeader.reqSeqOrBatNo = tmpHeader.reqSeqID;
        }
		tmpHeader.billNo = xmlReader.getSimpleText("BillNo");
        tmpHeader.ownAct=xmlReader.getSimpleTextNotNull("ActNum");
        if ("9188".equals(tmpHeader.transType) || "9188-ReSend".equals(tmpHeader.transType)) {
        	tmpHeader.isBatRec = true;
        	tmpHeader.isBatPay = false;
        } else if ("1988".equals(tmpHeader.transType) || "1988-ReSend".equals(tmpHeader.transType)) {
        	tmpHeader.isBatRec = false;
        	tmpHeader.isBatPay = true;
        }

        if("1".equals(xmlReader.getSimpleTextNotNull("BusiType"))
                &&"1".equals(xmlReader.getSimpleTextNotNull("OperType"))
                &&"B006".equals(tmpHeader.transType)){
            tmpHeader.isQryBillApply = true;
        }
        if (StringHelper.isNullOrEmpty(tmpHeader.corporation)) {
        	tmpHeader.corporation = "5000001";
        }

        if (StringHelper.isNullOrEmpty(tmpHeader.group)) {
        	tmpHeader.group = "Default";
        }

        if (xmlReader.getSimpleText("PayDate") != null) {
            tmpHeader.payDateTime = xmlReader.getSimpleText("PayDate") + " " + xmlReader.getSimpleTextNotNull("PayTime");
        }

        //如果是批量出票交易或者批量出票结果查询，需要读取协议号
        if(StringHelper.hasAnyChar(tmpHeader.transType) &&
                ("B113".equals(tmpHeader.transType)||"B010".equals(tmpHeader.transType))){
            tmpHeader.protocolNo = xmlReader.getSimpleText("ProtocolNo");
        }
        if(StringHelper.isNullOrEmpty(tmpHeader.bankCode) && StringHelper.isNullOrEmpty(tmpHeader.transType)){
        	String fgCommandCode = xmlReader.getFirstText("/Root/Head/CommandCode");
        	if(StringHelper.hasAnyChar(fgCommandCode)){
        		String fgCorpBankCode = xmlReader.getFirstText("/Root/Head/CorpBankCode");
        		if(StringHelper.hasAnyChar(fgCorpBankCode)){
        			tmpHeader.bankCode = "FnGrd"+fgCorpBankCode;
        		}else{
        			tmpHeader.bankCode = "FnGrd01";
        		}
        		tmpHeader.transType = "SyncTransaction";//明细推送
        		tmpHeader.commandCode = fgCommandCode;
        	}
        }
        tmpHeader.setTransType(tmpHeader.transType);
        return tmpHeader;
    }

    public static ReqRespHeader getReqRespHeader(Map<String,String> params) throws Exception {
        ReqRespHeader tmpHeader = new ReqRespHeader();
        tmpHeader.bankCode = params.get("BankCode");
        tmpHeader.srcBankCode = tmpHeader.bankCode;
        if (tmpHeader.bankCode.startsWith("CSRS")) {
            tmpHeader.bankCode = "CSRSYBT11";
        }
        tmpHeader.transType = params.get("TransType");
        tmpHeader.step = params.get("Step");
        tmpHeader.logTransID = params.get("LogTransID");
        tmpHeader.corporation = params.get("Entity");//
        tmpHeader.group = params.get("SystemCode");
        if(StringHelper.isNullOrEmpty(tmpHeader.group)){
            tmpHeader.group = params.get("Group");
        }
        tmpHeader.transSeqID = params.get("TransSeqID");
        tmpHeader.tenant = params.get("Tenant");
        if(StringHelper.isNullOrEmpty(tmpHeader.tenant)){
            tmpHeader.tenant = "";
        }
        tmpHeader.commandCode = params.get("CommandCode");
        tmpHeader.actBankType = params.get("ActBankType");
        tmpHeader.transTime = params.get("TransTime");
        tmpHeader.psselNum = params.get("PsselNum");
        tmpHeader.reqSeqID = params.get("ReqSeqID");
        if(StringHelper.isNullOrEmpty(tmpHeader.reqSeqID)){
            tmpHeader.reqSeqID = params.get("RdSeq");
        }
        if(StringHelper.isNullOrEmpty(tmpHeader.reqSeqOrBatNo)){
            tmpHeader.reqSeqOrBatNo = tmpHeader.reqSeqID;
        }
        tmpHeader.ownAct=params.get("OurBankAccount");
        if (StringHelper.isNullOrEmpty(tmpHeader.corporation)) {
            tmpHeader.corporation = "5000001";
        }
        if (StringHelper.isNullOrEmpty(tmpHeader.group)) {
            tmpHeader.group = "Default";
        }
        if(StringHelper.isNullOrEmpty(tmpHeader.bankCode) && StringHelper.isNullOrEmpty(tmpHeader.transType)){
            String fgCommandCode = params.get("CommandCode");
            if(StringHelper.hasAnyChar(fgCommandCode)){
                String fgCorpBankCode = params.get("CorpBankCode");
                if(StringHelper.hasAnyChar(fgCorpBankCode)){
                    tmpHeader.bankCode = "FnGrd"+fgCorpBankCode;
                }else{
                    tmpHeader.bankCode = "FnGrd01";
                }
                tmpHeader.transType = "SyncTransaction";//明细推送
                tmpHeader.commandCode = fgCommandCode;
            }
        }
        tmpHeader.setTransType(tmpHeader.transType);
        return tmpHeader;
    }
    
    public String getLogTableName(Date p_date, Connection p_conn) {
        if (dspSet.dbConnectionSet == null) {
            return null;
        }
        if (dspSet.autoCreateDbTable == false) {
            return "BANKLOGS";
        }
        String tmpYearMonth = Format.Date6YearMonth.format(p_date);
        if (hashTableName.containsKey(tmpYearMonth)) {
            return hashTableName.get(tmpYearMonth);
        } else {
            synchronized (lockMutex) {//同步代码

                if (hashTableName.containsKey(tmpYearMonth)) {
                    return hashTableName.get(tmpYearMonth);
                }

                String tableName = "BANKLOGS" + tmpYearMonth;
                //PreparedStatement pre = null;
                //Statement createStatement = null;
                //ResultSet result = null;
                try {
                    String sql = "select count(*) from user_tables where TABLE_NAME=?";
                    /*
                    pre = p_conn.prepareStatement(sql);
                    pre.setString(1, tableName.toUpperCase());
                    result = pre.executeQuery();
                    if (result.next()) {
                        int countRD = result.getInt(1);
                        if (countRD == 0) {
                            //创建日志表
                            try {
                                createStatement = p_conn.createStatement();
                                createStatement.executeUpdate("create table BANKLOGS" + tmpYearMonth + "(" +
                                        "  URID        VARCHAR2(24)," +
                                        "  BUSTIME   DATE," +
                                        "  BEGINTIME   DATE," +
                                        "  ENDTIME     DATE," +
                                        "  REQSEQID    VARCHAR2(32)," +
                                        "  TRANSSEQID  VARCHAR2(32)," +
                                        "  CREATETIME  DATE default sysdate not null," +
                                        "  BANKCODE    VARCHAR2(20)," +
                                        "  TRANSTYPE   VARCHAR2(20)," +
                                        "  COMMANDCODE VARCHAR2(20)," +
                                        "  DSPCODE     VARCHAR2(16)," +
                                        "  BANKFRONTCODE     VARCHAR2(20)," +
                                        "  CORPORATION VARCHAR2(32)," +
                                        "  ACTGROUP    VARCHAR2(32)," +
                                        "  LOGSUBFILE  VARCHAR2(128)," +
                                        "  LOGDATA     NCLOB)");
                                createStatement.executeUpdate("create index IX_LOG_URID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)");
                                createStatement.executeUpdate("create index IX_LOG_BUTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (BUSTIME)");
                                createStatement.executeUpdate("create index IX_LOG_BTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (BEGINTIME)");
                                createStatement.executeUpdate("create index IX_LOG_ETIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (ENDTIME)");
                                createStatement.executeUpdate("create index IX_LOG_CTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (CREATETIME)");
                                createStatement.executeUpdate("create index IX_LOG_RID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (REQSEQID)");
                                createStatement.executeUpdate("create index IX_LOG_TID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (TRANSSEQID)");
*/
                    Map<String, Object> countMap = JDBCHelper.execQuerySingle(p_conn, sql, new Object[]{tableName.toUpperCase()});
                    if (countMap != null && countMap.size() > 0) {
                        int countRD = Integer.parseInt(String.valueOf(countMap.get("count(*)")));
                        if (countRD == 0) {
                            //创建日志表
                            try {
                                String createTableSql = "create table BANKLOGS" + tmpYearMonth + "(" +
                                        "URID        VARCHAR2(24)," +
                                        "BUSTIME   DATE," +
                                        "BEGINTIME   DATE," +
                                        "ENDTIME     DATE," +
                                        "REQSEQID    VARCHAR2(32)," +
                                        "TRANSSEQID  VARCHAR2(32)," +
                                        "CREATETIME  DATE default sysdate not null," +
                                        "BANKCODE    VARCHAR2(20)," +
                                        "TRANSTYPE   VARCHAR2(20)," +
                                        "COMMANDCODE VARCHAR2(20)," +
                                        "DSPCODE     VARCHAR2(16)," +
                                        "BANKFRONTCODE     VARCHAR2(20)," +
                                        "CORPORATION VARCHAR2(32)," +
                                        "ACTGROUP    VARCHAR2(32)," +
                                        "LOGSUBFILE  VARCHAR2(128)," +
                                        "LOGDATA     NCLOB)";
                                JDBCHelper.update(p_conn, createTableSql, new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_URID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_BUTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_BTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_ETIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_CTIME" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_RID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                JDBCHelper.update(p_conn, "create index IX_LOG_TID" + tmpYearMonth + " on BANKLOGS" + tmpYearMonth + " (URID)", new Object[]{});
                                hashTableName.put(tmpYearMonth, tableName);
                                return hashTableName.get(tmpYearMonth);
                            } catch (SQLException ex) {
                                FGBiz.startLog.exception("DSPCenter.getLogTableName", ex);
                                if (ex.getMessage().indexOf("ORA-00955") >= 0) {//表已存在
                                    hashTableName.put(tmpYearMonth, tableName);
                                    return hashTableName.get(tmpYearMonth);
                                }
                            }
                        } else {
                            hashTableName.put(tmpYearMonth, tableName);
                            return hashTableName.get(tmpYearMonth);
                        }
                    } else {
                        return null;
                    }
                } catch (Exception e) {
                	FGBiz.startLog.exception("DSPCenter.getLogTableName", e);
                }
            }
        }
        return null;
    }
    
    public String refreshDSPSystem() throws Exception{
    	String retValue = "";
     	String tmpFileName = dspSet.rootDirPath + File.separator + "config" + File.separator + "DSPSystem.xml";
         File tmpFile = new File(tmpFileName);
         if (tmpFile.exists()) {
        	 boolean oriUseDBConn = dspSet.useDBConn;
        	 BankConfig tmpConfig = new BankConfig(tmpFileName);
        	 retValue = dspSet.refreshDspSet(tmpConfig);
        	 dspCode = dspSet.dspCode;
        	 dbLogOnlySavePath = dspSet.dbLogOnlySavePath;
        	 dbConnectionSet = dspSet.dbConnectionSet;
        	 enableDbLog = dspSet.enableDbLog;
        	 bankLogsFirstDir = dspSet.bankLogsFirstDir;
        	 dataDirPath = dspSet.dataDirPath;

        	 convertBankArea = dspSet.convertBankArea;
             convertPayState = dspSet.convertPayState;
             enableCacheCurTrans = dspSet.enableCacheCurTrans;
             enableCacheHisTrans = dspSet.enableCacheHisTrans;
             enableAutoTodayTrans = dspSet.enableAutoTodayTrans;
             enableAutoHisTrans = dspSet.enableAutoHisTrans;
             enableCheckTransSeqID = dspSet.enableCheckTransSeqID;
             bankLogsDirPath = dspSet.bankLogsDirPath;
             charset = dspSet.charsetName;
             qryByEachDay7516 = dspSet.qryByEachDay7516;
             disableAibank = dspSet.disableAibank;
        	 dspConfig = tmpConfig;
        	 //useDBConn变为true才需要
        	 if (!oriUseDBConn && dspSet.useDBConn && dspSet.enableBankPayInfo) {
        		 Connection tmpConn = null;
        		 try{
        			 tmpConn = dspSet.dbConnectionSet.getConnection();
        			 FGBiz.startLog.addLogNoTime("开始初始化支付信息表");
                     if(BankPayInfo.init(tmpConn, dspSet.payInfoTableCount, dspSet.payInfoActiveDate)) {
                    	 FGBiz.startLog.addLog("支付信息表初始化完毕");
                     }else{
                         throw new Exception("支付信息表初始化异常");
                     }
        		 }catch (Exception ex) {
                     throw new Exception(ex);
                 } finally {
                     if (tmpConn != null) {
                         tmpConn.close();
                     }
                 }
             }

         }else{
          	retValue = "不存在配置文件"+tmpFileName+"。";
          	FGBiz.startLog.error("DSPCenter.refreshDSPSystem", retValue);
         }

         return retValue;
    }

    public String refreshBankFront(String refreshType, String refreshKey) throws Exception{
    	return bankFrontCenter.refreshBankFront(dspSet, refreshType, refreshKey);
    }
    
    public String refreshBankFrontTokenByUrid(String pUrid) throws Exception{
    	return bankFrontCenter.refreshBankFrontToken(dspSet, "ByURID", pUrid);
    }

    /**获取所有租户*/
    public ArrayList<String> getDistinctTenant(){
    	ArrayList<String> tList = new ArrayList<String>();
    	Iterator<String> iter = bankFrontCenter.hashMapBankFront.keySet().iterator();
        while (iter.hasNext()) {
            String eachKey = iter.next();
            for (BankFront eachFront : bankFrontCenter.hashMapBankFront.get(eachKey).listBankFront) {
            	if(!tList.contains(eachFront.tenant)){
            		tList.add(eachFront.tenant);
            	}
            }
        }
    	return tList;
    }
    
    public String getRuntimeJsonList(){
    	return bankFrontCenter.getRuntimeJsonList();
    }

    public String getBankFrontJsonList(){
    	StringBuilder sbJson = new StringBuilder();
    	sbJson.append("[");
    	int rdCount=0;
    	Iterator<String> iter = bankFrontCenter.hashMapBankFront.keySet().iterator();
        while (iter.hasNext()) {
            String eachKey = iter.next();
            for (BankFront eachFront : bankFrontCenter.hashMapBankFront.get(eachKey).listBankFront) {
            	rdCount++;
            	if(rdCount>1){
            		sbJson.append(",");
            	}
            	sbJson.append("{");
            	sbJson.append("\"urid\":\""+eachFront.urid.trim()+"\"");
            	sbJson.append(",\"code\":\""+eachFront.code.trim()+"\"");
            	sbJson.append(",\"name\":\""+eachFront.name.trim()+"\"");
            	sbJson.append(",\"bkCode\":\""+eachFront.bankCode.trim()+"\"");
            	sbJson.append(",\"payMaxCc\":\""+eachFront.frontPayMaxCcCount+"\"");
            	sbJson.append(",\"qryMaxCc\":\""+eachFront.frontQueryMaxCcCount+"\"");
                sbJson.append(",\"eleMaxCc\":\""+eachFront.frontEleMaxCcCount+"\"");
                sbJson.append(",\"eleQryMaxCc\":\""+eachFront.frontEleQueryMaxCcCount+"\"");
            	sbJson.append(",\"payConCurr\":\""+eachFront.getPayConcurrent()+"\"");
            	sbJson.append(",\"qryConCurr\":\""+eachFront.getQryConcurrent()+"\"");
            	sbJson.append(",\"corp\":\""+eachFront.corporation.trim()+"\"");
            	sbJson.append(",\"group\":\""+eachFront.group.trim()+"\"");
            	sbJson.append(",\"status\":\""+eachFront.getFrontStatusDesc()+"\"");
            	//sbJson.append(",\"svr\":\""+eachFront.getIpPortOrUrl().trim()+"\"");
            	sbJson.append("}");
            }
        }
        sbJson.append("]");
        return sbJson.toString();
    }
    
    public String getBankCodeByUrid(String pUrid){
    	BankFront bf = bankFrontCenter.getBankFrontByUrid(pUrid);
    	if(bf!=null){
    		return bf.bankCode;
    	}
    	return null;
    }
    
    /**获取前置机状态*/
    public String getBankFrontStatus(RequestNIO p_bizO, ReqRespHeader p_header, String p_reqStr) {
        RetAtsBankFrontStatus retAts = new RetAtsBankFrontStatus(p_header);
        retAts.writeTop();
        try {
            retAts.writeRespCode("0");
            retAts.writeRespInfo("");
            
            boolean isChkSys = false;//是否指定线路
            HashMap<String,String> mapSys = new HashMap<String,String>();
            XmlTextReader reqReader = new XmlTextReader(p_reqStr);
            String directSys = reqReader.getSimpleText("DirectSys");
            if(StringHelper.hasAnyChar(directSys)){//指定线路
            	isChkSys = true;
            	String[] spSys = directSys.split(",");
            	for(int i=0;i<spSys.length;i++){
            		mapSys.put(spSys[i].toUpperCase(), spSys[i]);
            	}
            }

            Iterator<String> iter = bankFrontCenter.hashMapBankFront.keySet().iterator();
            while (iter.hasNext()) {
                String eachKey = iter.next();
                for (BankFront eachFront : bankFrontCenter.hashMapBankFront.get(eachKey).listBankFront) {
                	if(isChkSys){
                		if(!mapSys.containsKey(eachFront.bankCode.toUpperCase())){
                			continue;
                		}
                	}
                	RetAtsFrontStatusDetail eachDetail = new RetAtsFrontStatusDetail();
                    eachDetail.urid = eachFront.urid;
                    eachDetail.code = eachFront.code;
                    eachDetail.name = eachFront.name;
                    eachDetail.entity = eachFront.corporation;
                    eachDetail.systemCode = eachFront.group;
                    eachDetail.server = eachFront.getIpPortOrUrl();

                    boolean needChk = true;
                    if (!"2".equals(eachFront.checkLevel)) {
                    if (eachFront.frontStatus.status == EnBfStatus.normal && eachFront.frontStatus.statusTime != null) {
                    	double pastMins = DateHelper.getDifferMins(new Date(), eachFront.frontStatus.statusTime);
                        if (pastMins < 5) {
                            needChk = false;
                        }
                    }
                    }
                    if (needChk) {
                        if (StringHelper.hasAnyChar(eachFront.frontStatus.cmdPckForCheck)) {
                            String atsPck = eachFront.frontStatus.getAtsPckForCheck();
                            XmlTextReader xmlReader = new XmlTextReader(atsPck);
                            ReqRespHeader tmpHeader = DSPCenter.getReqRespHeader(xmlReader);
                            DealDirectBank tmpDealDirect = new DealDirectBank(atsPck);
                            tmpDealDirect.setBankFront(eachFront);
                            tmpDealDirect.dealDirectTrans(p_bizO, tmpHeader, xmlReader);
                        } else {
                            eachFront.pingServer();
                        }
                    }

                    eachDetail.status = eachFront.frontStatus.status;
                    eachDetail.statusInfo = eachFront.frontStatus.statusInfo;
                    eachDetail.StatusTime = eachFront.frontStatus.statusTime;
                    retAts.writeRetDetail(eachDetail);
                }
            }

            Transmit tmpTransmit = new Transmit(p_bizO, FGBiz.dspCenter.rootDirPath);
            ArrayList<String[]> transmitList = tmpTransmit.getTransmitIpPortList();
            if (transmitList != null && transmitList.size() > 0) {
                for (int i = 0; i < transmitList.size(); i++) {
                    Date tmpDateNow = new Date();
                    tmpTransmit.setIpAndPort(transmitList.get(i)[0], transmitList.get(i)[1]);
                    String respBody = tmpTransmit.doTransmit(p_bizO.reqSocketReceiver.getContentBytes());
                    if (respBody.indexOf("<") >= 0) {
                        XmlTextReader xmlReader = new XmlTextReader(respBody);
                        while (xmlReader.read(retAts.PATH_Detail)) {
                            retAts.writeXElement(xmlReader.readedXElement);
                        }
                    } else {
                        RetAtsFrontStatusDetail eachDetail = new RetAtsFrontStatusDetail();
                        eachDetail.name = "转发目的DSP";
                        eachDetail.server = transmitList.get(i)[0] + ":" + transmitList.get(i)[1];
                        eachDetail.status = EnBfStatus.exception;
                        eachDetail.statusInfo = respBody;
                        eachDetail.StatusTime = tmpDateNow;
                        retAts.writeRetDetail(eachDetail);
                    }
                }
            }
        } catch (Exception e) {
            retAts.writeException(e);
        }
        retAts.writeTail();
        return retAts.getRetAtsString();
    }
    
    /**启动渠道侦听服务，用于接收各渠道的通知等*/
    public void startListener(){
    	//HttpListener listener = new HttpListener(706, "utf-8", "SHIE01");
    	//new Thread(listener).start();
    	
    	HashSet<String> filterBf = new HashSet<String>();

    	for (BankFrontBalance bfBalance : bankFrontCenter.hashMapBankFront.values()) {
        	for (BankFront tmpBankFront : bfBalance.listBankFront) {
        		if(filterBf.contains(tmpBankFront.urid)){
        			continue;
        		}
        		filterBf.add(tmpBankFront.urid);
        		if(tmpBankFront.hashListenerSet != null && tmpBankFront.hashListenerSet.size() > 0){
            		for (ListenerSet eachSet : tmpBankFront.hashListenerSet.values()) {
            			if(eachSet.enable && eachSet.listenerPort > 0){
            				String lsnAddr = "";
            				if("socket".equals(eachSet.protocol)){
            					lsnAddr = FGBiz.localHostIp+":" + eachSet.listenerPort;
            				}else if("https".equals(eachSet.protocol)){
            				    lsnAddr = "https://" + FGBiz.localHostIp+":" + eachSet.listenerPort + eachSet.prefix;
                                if(eachSet.listenerPort == 443){
                                    lsnAddr = "https://" + FGBiz.localHostIp + eachSet.prefix;
                                }
                                if("".equals(eachSet.keyStore) || "".equals(eachSet.keyStorePwd) || "".equals(eachSet.encryProtocol)){
                                    FGBiz.startLog.addLogNoTime(tmpBankFront.bankCode + "启动前置机"+tmpBankFront.code+"-"+tmpBankFront.name+"侦听，端口："+eachSet.listenerPort+"，地址："+lsnAddr
                                            +"失败，原因：密钥库或密钥库密码或加密协议未配置");
                                    continue;
                                }
                            }else{
            					lsnAddr = "http://" + FGBiz.localHostIp+":" + eachSet.listenerPort + eachSet.prefix;
            					if(eachSet.listenerPort == 80){
                					lsnAddr = "http://" + FGBiz.localHostIp + eachSet.prefix;
                				}
            				}
            				FGBiz.startLog.addLogNoTime(tmpBankFront.bankCode + "启动前置机"+tmpBankFront.code+"-"+tmpBankFront.name+"侦听，端口："+eachSet.listenerPort+"，地址："+lsnAddr);
            				try{
            					if(mapListener == null){
            						mapListener = new HashMap<Integer,HttpListener>();
            					}
            					if(mapListener.containsKey(eachSet.listenerPort)){
            						mapListener.get(eachSet.listenerPort).addListenerSet(eachSet);
            					}else{
            						HttpListener tmpListener = new HttpListener(eachSet);
            						mapListener.put(eachSet.listenerPort, tmpListener);
            					}

            				}catch(Exception ex){
            					FGBiz.startLog.exception("DSPCenter.startListener", ex);
            				}
            			}
            		}
            	}
        	}
        }
    	
    	String tmpFileName = dspSet.rootDirPath + File.separator + "config" + File.separator + "Web.xml";
        File tmpFile = new File(tmpFileName);
        if (tmpFile.exists()) {
        	String strXml = FileHelper.readToString(tmpFile, "utf-8");
        	XmlTextReader xmlReader = new XmlTextReader(strXml);
        	try {
				if(xmlReader.read("/config/listenerSet")){
					ListenerSet eachSet = new ListenerSet();
					eachSet.fromXElement(xmlReader.readedXElement);
					if(eachSet.enable){
						
						if(mapListener == null){
    						mapListener = new HashMap<Integer,HttpListener>();
    					}
						
						
						eachSet.bankFront = new BankFront();
						eachSet.bankFront.bankCode = "dsp";
						
						HttpListener tmpListener = new HttpListener(eachSet);
						
						mapListener.put(eachSet.listenerPort, tmpListener);
						String lsnAddr = "";
						if("https".equals(eachSet.protocol)){
        				    lsnAddr = "https://" + FGBiz.localHostIp+":" + eachSet.listenerPort + eachSet.prefix;
                            if(eachSet.listenerPort == 443){
                                lsnAddr = "https://" + FGBiz.localHostIp + eachSet.prefix;
                            }
                            if("".equals(eachSet.keyStore) || "".equals(eachSet.keyStorePwd) || "".equals(eachSet.encryProtocol)){
                                FGBiz.startLog.addLogNoTime("启动Web指令侦听，端口："+eachSet.listenerPort+"，地址："+lsnAddr
                                        +"失败，原因：密钥库或密钥库密码或加密协议未配置");
                            }
                        }else{
        					lsnAddr = "http://" + FGBiz.localHostIp+":" + eachSet.listenerPort + eachSet.prefix;
        					if(eachSet.listenerPort == 80){
            					lsnAddr = "http://" + FGBiz.localHostIp + eachSet.prefix;
            				}
        				}
        				FGBiz.startLog.addLogNoTime("启动Web指令侦听，端口："+eachSet.listenerPort+"，地址："+lsnAddr);
						
					}
				}
			} catch (NumberFormatException e) {
				FGBiz.startLog.exception("DSPCenter.startListener", e);
			} catch (Exception e) {
				FGBiz.startLog.exception("DSPCenter.startListener", e);
			}
        }

    	if(mapListener != null && mapListener.size()>0){
    		for(HttpListener eachListener:mapListener.values()){
    			try{
    				if(threadArray == null){
    					threadArray = new ArrayList<Thread>();
    				}

    				Thread eachThread = new Thread(eachListener);
    				eachThread.start();
    				threadArray.add(eachThread);
    			}catch(Exception ex){
    				FGBiz.startLog.exception("DSPCenter.startListener", ex);
				}
        	}
    	}

    }
    
    public String stopListener(){
    	StringBuilder sbMsg = new StringBuilder();
    	if(mapListener != null && mapListener.size() > 0){
    		for(Map.Entry<Integer,HttpListener> eachEntry : mapListener.entrySet()){
    			String eStr = eachEntry.getValue().stop();
    			if(StringHelper.hasAnyChar(eStr)){
    				if(sbMsg.length()>0){
    					sbMsg.append("\r\n");
    				}
    				sbMsg.append(eStr);
    			}
    		}
    	}
    	return sbMsg.toString();
    }

    /**启动渠道的定时任务*/
    public void startScheduleTask(){
    	//long minIntervalSec = 10;
    	for (BankFrontBalance bfBalance : bankFrontCenter.hashMapBankFront.values()) {
        	for (BankFront tmpBankFront : bfBalance.listBankFront) {
        		if(tmpBankFront.hashTimerSet != null && tmpBankFront.hashTimerSet.size() > 0){
            		for (TaskTimerSet eachSet : tmpBankFront.hashTimerSet.values()) {
            			if(eachSet.enable && eachSet.intervalSecs > 0){
            				//if(eachSet.intervalSecs<minIntervalSec){
            				//	minIntervalSec = eachSet.intervalSecs;
            				//}
            				
            				if(taskList == null){
            					taskList = new ArrayList<TaskTimerSet>();
            				}
            				taskList.add(eachSet);
            			}
            		}
            	}
        	}
        }
    	if(taskList != null && taskList.size()>0){
    		pool = Executors.newScheduledThreadPool(taskList.size());
    		for(final TaskTimerSet eachTaskSet : taskList){
    			final TimerTask task1 = new TimerTask() {
                    public void run() {
                    	TaskExecutor taskExecutor = new TaskExecutor();
                    	taskExecutor.execTask(eachTaskSet);
                    }
                };
                //pool.scheduleAtFixedRate(task1, 0, eachTaskSet.intervalSecs, TimeUnit.SECONDS);
                pool.scheduleWithFixedDelay(task1, 0, eachTaskSet.intervalSecs, TimeUnit.SECONDS);
                FGBiz.startLog.addLogNoTime(eachTaskSet.bankFront.bankCode + "启动前置机"+eachTaskSet.bankFront.code+"-"+eachTaskSet.bankFront.name+"定时任务，轮询间隔时间："+eachTaskSet.intervalSecs+"秒，任务名称列表："+eachTaskSet.taskNameList);
    		}
    	}
    }
    
    public String stopScheduleTask(){
    	if(pool != null){
    		try{
    			pool.shutdown();
    			return "渠道定时任务正常关闭";
    		}catch(Throwable e){
    			FGBiz.startLog.exception("DSPCenter.stopScheduleTask", e);
    			return "关闭渠道定时任务出现异常：" + LogHelper.getStackTrace(e);
    		}
    	}else{
    		return "";
    	}
    }

    public String getDSPLog(RequestNIO p_bizO, ReqRespHeader p_header, String p_reqStr) {
        RetAtsDSPLog retAts = new RetAtsDSPLog(p_header);
        retAts.writeTop();
        RetAtsDSPLogDetail tmpRetDetail = new RetAtsDSPLogDetail();

        try {
            String logTransID = p_header.logTransID;
            String traceID = logTransID.split("_")[3];
            String logFilePath = Format.DateForLogFormat.format(Format.DateTime14Format.parse(logTransID.split("_")[2])).replace("-", File.separator) + File.separator + logTransID.split("_")[0];

            // 主机读取日志在本机
            String logFileDir = FGBiz.dspCenter.dspSet.bankLogsDirPath + File.separator + FGBiz.dspCenter.dspSet.bankLogsFirstDir + File.separator + logFilePath;
            if (FileHelper.existFile(logFileDir)) {
                File[] logFiles = new File(logFileDir).listFiles();
                for(File logFile : logFiles) {
                    if (traceID.equalsIgnoreCase(logFile.getName().substring(logFile.getName().lastIndexOf("_")+1).replace(".txt",""))) {
                        tmpRetDetail.respCode = "0";
                        tmpRetDetail.dspMsg = FileHelper.readFileText(logFile.getAbsolutePath(), FGBiz.dspCenter.dspSet.charsetName);
                    }
                }
            }

            if (StringHelper.isNullOrEmpty(tmpRetDetail.dspMsg)) {
                ClusterCenter clusterCenter = new ClusterCenter();
                if(clusterCenter.enable && clusterCenter.otherHostList!= null && clusterCenter.otherHostList.size()>0){
                    for(HostInfo eachHost : clusterCenter.otherHostList) {
                        if (StringHelper.hasAnyChar(eachHost.addr)) {
                            // 主机读取日志不在本机,需要在集群dsp中读取日志
                            DspClient dspClient = new DspClient(eachHost.addr);
                            dspClient.charsetName = FGBiz.dspCenter.dspSet.charsetName;
                            TcpReceiver tcpRec = dspClient.getFile(FileType.bankFile, logFilePath + "_" + traceID);
                            if (tcpRec.isCompleted) {
                                tmpRetDetail.respCode = "0";
                                tmpRetDetail.dspMsg = new String(tcpRec.recBytes, tcpRec.contentStartIndex, tcpRec.contentLength, tcpRec.charsetName);
                            }
                        } else {
                            tmpRetDetail.respCode = "-1";
                            tmpRetDetail.respInfo = "'Cluster.xml'配置字段'LocalHost'字段为空!";
                        }
                    }
                }
            }

            if (StringHelper.isNullOrEmpty(tmpRetDetail.dspMsg)) {
                tmpRetDetail.respCode = "-1";
                tmpRetDetail.respInfo = "当前遍历dsp集群机器内均无法获取该日志请求文件,请确认请求参数'LogTransID'是否正确!";
            }

            retAts.writeRetDetail(tmpRetDetail);
        } catch (Exception e) {
            tmpRetDetail.respCode = "-1";
            tmpRetDetail.respInfo = LogHelper.getStackTrace(e);
        }
        retAts.writeTail();
        return retAts.getRetAtsString();
    }
}